package com.glodon.cloudt.rest.client.impl;

import com.alibaba.fastjson.JSONObject;
import com.glodon.cloudt.rest.client.RestServiceClient;
import com.glodon.cloudt.rest.client.RestServiceClientSupport;
import com.glodon.cloudt.rest.client.data.HmacRestAuthInfo;
import com.glodon.cloudt.rest.client.data.LicenseInfo;
import com.glodon.cloudt.rest.client.data.RestAuthInfo;
import com.glodon.cloudt.rest.client.data.RestResponseInfo;
import com.glodon.cloudt.rest.client.exception.AuthenticateException;
import com.glodon.cloudt.rest.client.exception.InvalidLicFileException;
import com.glodon.cloudt.rest.client.exception.InvalidUriException;
import com.glodon.cloudt.rest.client.exception.NoAuthenticateException;
import com.glodon.cloudt.rest.client.utils.CryptoUtils;
import com.glodon.cloudt.rest.client.utils.LicenseUtils;
import com.glodon.cloudt.rest.client.utils.StringUtils;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.DefaultHttpClient;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

/**
 * 只是为了 覆盖广联达jar包中的绑定设备
 */
public class HmacRestServiceClientNew extends RestServiceClientSupport {
    private static final String PARAM_SIGNATURE = "t-cloud-rest-signature";
    private static final String PARAM_COMPUTER_ID = "t-cloud-rest-computer-id";
    private static final String PARAM_EXPIRES = "t-cloud-rest-timestamps";
    private static final String PARAM_ACCESS_ID = "t-cloud-rest-access-id";
    private static final String PARAM_COMPUTER_DESCRIPTION = "t-cloud-rest-computer-description";
    private static final String KEY_MAC_SHA1 = "HmacSHA1";
    private static final String errorMessage = "未找到授权文件";
    private static final HmacRestServiceClientNew instance = new HmacRestServiceClientNew();
    private LicenseInfo licenseInfo;
    private String computerId;
    private String computerDescription;
    private HmacRestAuthInfo hmacRestAuthInfo;

    // public static void main(String[] args) {
    //     HmacRestServiceClient hmacRestServiceClient = new HmacRestServiceClient();
    //
    //     System.out.println("computerId：" + hmacRestServiceClient.computerId);
    //     System.out.println("computerDescription：" + hmacRestServiceClient.computerDescription);
    // }

    public HmacRestServiceClientNew() {
        this.computerId = "";
        // this.computerId = HardwareFeatureManager.computeComputerId();
        // 固定即可！
        this.computerId = "B0E3C6294FABE4DDAC641DBE8E61DA9B";
        // this.computerDescription = HardwareFeatureManager.getComputerDescription();
        // 固定即可！
        this.computerDescription = "N/A";
    }

    @Override
    public String getRestRootAddress() {
        return this.licenseInfo == null ? "" : this.licenseInfo.getRootAddress();
    }

    public static RestServiceClient getInstance() {
        return new HmacRestServiceClientNew();
    }

    @Override
    protected void checkAuthentication() throws NoAuthenticateException {
        if (this.licenseInfo == null) {
            throw new InvalidLicFileException(errorMessage);
        }
    }

    @Override
    protected void innerInitRequest(DefaultHttpClient httpClient, HttpRequestBase requestBase, String method) {
        long timestamps = new Date().getTime();

        requestBase.addHeader(PARAM_COMPUTER_ID, this.computerId);
        requestBase.addHeader(PARAM_ACCESS_ID, this.licenseInfo.getAccessId());
        requestBase.addHeader(PARAM_EXPIRES, String.valueOf(timestamps));
        requestBase.addHeader(PARAM_COMPUTER_DESCRIPTION, this.computerDescription);
        String url = requestBase.getURI().getPath();
        String query = requestBase.getURI().getRawQuery(); // URL 中请求参数
        if (!StringUtils.isEmpty(query)) {
            url = url + "?" + query;
        }
        String signature = getSignature(url.toUpperCase(Locale.CHINA) + "\n" + method.toUpperCase(Locale.CHINA) + "\n" + timestamps + "\n" + this.licenseInfo.getAccessId(), this.licenseInfo.getSecret());
        requestBase.addHeader(PARAM_SIGNATURE, signature);
    }

    @Override
    protected Map<String, String> getHeaders() {
        return this.hmacRestAuthInfo.getHeaders();
    }

    @Override
    public void authenticate(RestAuthInfo authInfo) throws AuthenticateException {
        if (authInfo == null) {
            throw new AuthenticateException("认证参数不能为NULL。");
        }
        if (!(authInfo instanceof HmacRestAuthInfo)) {
            throw new AuthenticateException("认证参数类型非法，应为[HmacRestAuthInfo]类型。");
        }
        this.hmacRestAuthInfo = (HmacRestAuthInfo) authInfo;
        if (!this.hmacRestAuthInfo.validate()) {
            throw new AuthenticateException("认证参数非法，请确认属性[licStream]和[licPath]存在一个可用。");
        }
        try (InputStream stream = this.hmacRestAuthInfo.getLicStream()) {
            if (stream != null) {
                this.licenseInfo = LicenseUtils.load(stream);
            } else {
                this.licenseInfo = LicenseUtils.load(this.hmacRestAuthInfo.getLicPath());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String createCloudSsoUrl(String service) throws NoAuthenticateException {
        if (this.licenseInfo == null) {
            return "";
        }
        long timestamp = System.currentTimeMillis();
        String credence = getCredence();
        String data1 = this.licenseInfo.getAccessId() + "|" + credence;
        String data12 = CryptoUtils.convertBytesToString(CryptoUtils.rsaEncode(data1).getBytes());
        String data = this.computerId + "|" + timestamp;
        String url = null;
        try {
            url = String.format("%s/identity/integrate/view?data=%s&data1=%s&service=%s", this.licenseInfo.getRootAddress(), CryptoUtils.encrypt(data, this.licenseInfo.getSecret()), data12, URLEncoder.encode(service, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return url;
    }

    @Override
    public String createCloudSsoUrlWithAccount(String service, String account, String productCode) {
        String service2;
        if (this.licenseInfo == null || StringUtils.isEmpty(account)) {
            return "";
        }
        String productCode2 = productCode == null ? "" : productCode;
        String data1 = this.licenseInfo.getAccessId() + "|123";
        String data12 = CryptoUtils.convertBytesToString(CryptoUtils.rsaEncode(data1).getBytes());
        String data = this.computerId + "|" + account;
        String data2 = CryptoUtils.encrypt(data, this.licenseInfo.getSecret());
        String url = null;
        try {
            if (!StringUtils.isEmpty(service)) {
                service2 = URLEncoder.encode(service, "UTF-8");
            } else {
                service2 = "";
            }
            url = String.format("%s/identity/integrate/account-sso?data=%s&data1=%s&service=%s&productCode=%s", this.licenseInfo.getRootAddress(), data2, data12, service2, productCode2);
        } catch (UnsupportedEncodingException e) {
        }
        return url;
    }


    private static String getSignature(String policy, String accessKey) {
        try {
            byte[] data = getUTF8Bytes(policy);
            byte[] encryptHMAC = encryptHMAC(data, accessKey);
            byte[] encode = Base64.getEncoder().encode(encryptHMAC);
            return new String(encode, StandardCharsets.UTF_8);
        } catch (InvalidKeyException | NoSuchAlgorithmException e) {
            return null;
        }
    }

    private static byte[] encryptHMAC(byte[] data, String key) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKey secretKey = new SecretKeySpec(getUTF8Bytes(key), KEY_MAC_SHA1);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    private static byte[] getUTF8Bytes(String content) {
        if (StringUtils.isEmpty(content)) {
            return new byte[0];
        }
        return StringUtils.getBytes(content);
    }

    private String getCredence() throws NoAuthenticateException {
        try {
            RestResponseInfo restResponseInfo = get(getRestRootAddress() + "/identity/extend/credence");
            JSONObject value = JSONObject.parseObject(restResponseInfo.getStringContent());
            if (value.getBoolean("success")) {
                return value.getString("data");
            }
            return null;
        } catch (InvalidUriException e) {
            return null;
        }
    }
}
